package com.hewanglan.auth.domain.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.gson.Gson;
import com.hewanglan.auth.common.enums.AuthUserStatusEnum;
import com.hewanglan.auth.common.enums.IsDeletedFlagEnum;
import com.hewanglan.auth.domain.bo.AuthUserBO;
import com.hewanglan.auth.domain.constants.AuthConstant;
import com.hewanglan.auth.domain.convert.AuthUserBOConverter;
import com.hewanglan.auth.domain.redis.RedisUtil;
import com.hewanglan.auth.domain.service.AuthUserDomainService;
import com.hewanglan.auth.infra.basic.entity.*;
import com.hewanglan.auth.infra.basic.service.*;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * (AuthUser)表服务实现类
 */
@Service
public class AuthUserDomainServiceImpl implements AuthUserDomainService {
    @Resource
    private AuthUserService authUserService;

    @Resource
    private AuthRoleService authRoleService;

    @Resource
    private AuthUserRoleService authUserRoleService;

    @Resource
    private AuthRolePermissionService authRolePermissionService;

    @Resource
    private AuthPermissionService authPermissionService;

    private String salt = "chicken";  //加盐，使用md5加密算法对用户密码进行加密

    @Resource
    private RedisUtil redisUtil;

    private String authPermissionPrefix = "auth.permission";

    private String authRolePrefix = "auth.role";

    private static final String LOGIN_PREFIX="loginCode";


    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(AuthUserBO authUserBO) {
        //检验用户是否存在,避免重复注册
        AuthUser existAuthUser=new AuthUser();
        existAuthUser.setUserName(authUserBO.getUserName());//openId
        List<AuthUser> existUser=authUserService.queryByCondition(existAuthUser);
        if(!existUser.isEmpty())//说明用户已经存在
        {
            return true;
        }
        AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBOToEntity(authUserBO);
        //对密码进行加密再保存到数据库中
        if(!StringUtils.isBlank(authUser.getPassword()))
        {
            authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(), salt));
        }
        authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
        authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        Integer count = authUserService.insert(authUser);
        //建立一个初步的角色的关联
        //要把当前用户的角色和权限刷到redis里
        /**
         * 用户注册后，需要修改insert方法返回新增用户的id
         * 用户默认与普通用户角色关联，还需要获取普通用户角色的id
         * 将两者的id插入到auth_user_role表中
         * 至此完成用户与角色的关联
         */
        AuthRole authRole = new AuthRole();
        authRole.setRoleKey(AuthConstant.NORMAL_USER);
        AuthRole roleResult = authRoleService.queryByCondition(authRole);
        Long roleId = roleResult.getId();
        Long userId = authUser.getId();
        AuthUserRole authUserRole = new AuthUserRole();
        authUserRole.setRoleId(roleId);
        authUserRole.setUserId(userId);
        authUserRole.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        authUserRoleService.insert(authUserRole);
        /**
         *与redis做交互
         */
        String roleKey = redisUtil.buildKey(authRolePrefix, authUser.getUserName());
        List<AuthRole> roleList = new LinkedList<>();
        roleList.add(authRole);
        redisUtil.set(roleKey, new Gson().toJson(roleList));

        AuthRolePermission authRolePermission=new AuthRolePermission();
        authRolePermission.setRoleId(roleId);
        List<AuthRolePermission> rolePermissionList = authRolePermissionService.
                queryByCondition(authRolePermission);

        List<Long> permissionIdList = rolePermissionList.stream()
                .map(AuthRolePermission::getPermissionId).collect(Collectors.toList());
        //根据permissionIdList查权限名称
        List<AuthPermission> permissionList = authPermissionService.queryByPermissionList(permissionIdList);
        String permissionKey = redisUtil.buildKey(authPermissionPrefix, authUser.getUserName());
        redisUtil.set(permissionKey, new Gson().toJson(permissionList));

        return count > 0;
    }

    @Override
    public Boolean update(AuthUserBO authUserBO) {
        AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBOToEntity(authUserBO);
        authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
        authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        Integer count = authUserService.update(authUser);
        //有任何更新，都要与缓存进行同步
        return count > 0;
    }

    @Override
    public Boolean delete(AuthUserBO authUserBO) {
        AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBOToEntity(authUserBO);
        authUser.setStatus(AuthUserStatusEnum.OPEN.getCode());
        authUser.setIsDeleted(IsDeletedFlagEnum.DELETED.getCode());
        Integer count = authUserService.update(authUser);
        //有任何更新，都要与缓存进行同步
        return count > 0;
    }

    @Override
    public Boolean changeStatus(AuthUserBO authUserBO) {
        AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBOToEntity(authUserBO);
        authUser.setStatus(AuthUserStatusEnum.CLOSE.getCode());
        authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        Integer count = authUserService.update(authUser);
        //有任何更新，都要与缓存进行同步
        return count > 0;
    }

    @Override
    public SaTokenInfo doLogin(String validCode) {
       String loginKey=redisUtil.buildKey(LOGIN_PREFIX,validCode);
       String openId=redisUtil.get(loginKey);

       AuthUserBO authUserBO=new AuthUserBO();
       authUserBO.setUserName(openId);
       //执行注册用户方法
        this.register(authUserBO);
        StpUtil.login(openId);
        SaTokenInfo saTokenInfo= StpUtil.getTokenInfo();
        return saTokenInfo;
    }

    @Override
    public AuthUserBO getUserInfo(AuthUserBO authUserBO) {
        AuthUser authUser = AuthUserBOConverter.INSTANCE.convertBOToEntity(authUserBO);
        List<AuthUser> userList = authUserService.queryByCondition(authUser);
        if(CollectionUtils.isEmpty(userList))
        {
            return new AuthUserBO();
        }
        AuthUser authUser1 = userList.get(0);
        return AuthUserBOConverter.INSTANCE.convertEntityToBO(authUser1);
    }
}
